﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using DomainModel;
using Microsoft.Practices.Unity;
using Microsoft.WindowsAzure.MediaServices.Client;
using MusicManagerDAO.Interfaces;

namespace MusicManager.BL
{
    public class MusicManagerBLMediaServicecs : IMusicManagerBL
    {
        [Dependency]
        public IUserDao UserDao { get; set; }
        [Dependency]
        public IMusicDao MusicDao { get; set; }

        // Read values from the App.config file.
        private static readonly string _mediaServicesAccountName ="musicmanagerms";
        private static readonly string _mediaServicesAccountKey =@"+10nTUKz1nMqIO2Z9ZAF5f+ONOGEY6eQLiUtaeiNcDg=";

        // Field for service context.
        private static CloudMediaContext _context = null;

        private List<string> usersLoggedIn = new List<string>();


        public bool CreateUser(int id, string user, string password)
        {
            try
            {
                TransUtil.DoInTransaction(s => AddUserInternal(s), new DomainModel.User(id, user, password));
            }
            catch (UserAlreadyExistsException)
            {
                return false;
            }
            return true;
        }

        public IEnumerable<User> GetUserList()
        {
            IEnumerable<User> users = TransUtil.DoInTransaction(() => UserDao.FindAll());
            if (users == null || !users.Any())
                return null;
            return users;
        }

        public void AddUserInternal(DomainModel.User user)
        {
            if (!UserDao.Insert(user))
                throw new UserAlreadyExistsException();
        }

        public bool Login(string username, string password, out string token)
        {
            User user = TransUtil.DoInTransaction(() => UserFindByNameAndPassword(username, password));
            if (user == null)
            {
                token = null;
                return false;
            }
            else
            {
                token = CreateToken(user.Id, user.Name, user.Password);
                usersLoggedIn.Add(token);
                return true;
            }

        }

        private string CreateToken(User user)
        {
            return CreateToken(user.Id, user.Name, user.Password);
        }

        private string CreateToken(int id, string name, string password)
        {
            return id + "_" + name + "_" + password;
        }

        private User UserFindByNameAndPassword(string username, string password)
        {
            return UserDao.FindByNameAndPassword(username, password);
        }

        public bool Logout(string user, string token)
        {
            if (usersLoggedIn.Contains(token))
            {
                usersLoggedIn.Remove(token);
                return true;
            }
            return false;
        }

        public bool AddMusic(string name, byte[] data, string token)
        {
            IEnumerable<User> users = TransUtil.DoInTransaction(() => UserDao.FindAll());
            if (users == null || !users.Any())
                return false;

            return TransUtil.DoInTransaction(() =>
            {
                User user = users.First(user1 => CreateToken(user1) == token);
                if (user == null) return false;

                IEnumerable<Music> music = MusicDao.FindAllForUser(user);
                if (music.Any(music1 => music1.Name == name))
                    return false;
                AddMusicToMediaService(name + "42" + token, data);
                return MusicDao.Insert(new Music(music.Count() + 1, user.Id, name, new byte[0]));
            });
        }

        public IEnumerable<string> GetPlaylist(string token)
        {
            IEnumerable<User> users = TransUtil.DoInTransaction(() => UserDao.FindAll());
            if (users == null || !users.Any())
                return new List<string>();
            User u = GetUserForToken(token);
            IEnumerable<Music> playlist = TransUtil.DoInTransaction(() => MusicDao.FindAllForUser(u));
            return playlist.Select(music => music.Name).ToList();
        }

        private User GetUserForToken(string token)
        {
            IEnumerable<User> users = TransUtil.DoInTransaction(() => UserDao.FindAll());
            if (users == null || !users.Any())
                return null;

            return TransUtil.DoInTransaction(() => users.FirstOrDefault(user1 => CreateToken(user1) == token));
        }

        public Music GetMusic(string name, string token)
        {
            Music music = MusicDao.FindByUserIdAndName(GetUserForToken(token), name);
            music.Song = GetMusicFromMediaService(name + 42 + token);
            return music;

            //IEnumerable<Music> playlist = GetPlaylistFull(token);
            //if (playlist == null || !playlist.Any())
            //    return null;

            //Music m = playlist.FirstOrDefault(music => music.Name == name);
            //if (m == null) return null;

            //return m;
        }

        private void AddMusicToMediaService(string name, byte[] data)
        {
            
            string user = name.Split(new string[] { "42" }, StringSplitOptions.None)[1];
            string songName = name.Split(new string[] { "42" }, StringSplitOptions.None)[0];
            string path = @"C:\" + songName + ".mp4";
            using (FileStream fs = new FileStream(path, FileMode.Create))
            {
                fs.Write(data, 0, data.Length);
            }

            if (_context == null)
                _context = new CloudMediaContext(_mediaServicesAccountName, _mediaServicesAccountKey);

            IAsset asset = null;
            IAssetFile file = null;

            foreach (var asset1 in _context.Assets)
            {
                if (asset1.Name == user)
                {
                    asset = asset1;
                    break;
                }
            }

            if (asset == null)
                asset = _context.Assets.Create(user, AssetCreationOptions.None);

            var fileName = Path.GetFileName(path);


            foreach (var assetFile1 in asset.AssetFiles)
            {
                if (assetFile1.Name == fileName)
                {
                    file = assetFile1;
                    break;
                }
            }
            if (file != null)
            {
                file.Delete();                
            }

            file = asset.AssetFiles.Create(fileName);

            IAccessPolicy accessPolicy = null;
            ILocator locator = null;
            
            
            if (_context.AccessPolicies.Count() >= 5)
            {
         
            }
            if(_context.AccessPolicies.Count() < 3)
            {
            accessPolicy = _context.AccessPolicies.Create(name, TimeSpan.FromDays(30),
                                                    AccessPermissions.Write | AccessPermissions.List);
            locator = _context.Locators.CreateLocator(LocatorType.Sas, asset, accessPolicy);
            }



            file.Upload(path);

            if (locator != null)
            locator.Delete();
            if (locator != null)
            accessPolicy.Delete();
        }


        private byte[] GetMusicFromMediaService(string name)
        {
            string path = @"C:\temp2.mp4";

            string user = name.Split(new string[] {"42"},StringSplitOptions.None)[1];
            string songName = name.Split(new string[] {"42"},StringSplitOptions.None)[0];

            IAsset asset = null;
            IAssetFile file = null;


            if (_context == null)
                _context = new CloudMediaContext(_mediaServicesAccountName, _mediaServicesAccountKey);

            foreach (var asset1 in _context.Assets)
            {
                if (asset1.Name == user)
                {
                    asset = asset1;
                    break;
                }
            }

            if (asset == null)
                return new byte[0];
            var accessPolicy = _context.AccessPolicies.Create(name, TimeSpan.FromDays(30),
                            AccessPermissions.Read | AccessPermissions.List);
            var locator = _context.Locators.CreateLocator(LocatorType.Sas, asset, accessPolicy,
                DateTime.UtcNow.AddMinutes(-5));
            foreach (var assetFile1 in asset.AssetFiles)
            {
                if (assetFile1.Name == songName + ".mp4")
                {
                    file = assetFile1;
                    break;
                }
            }

            if (file == null)
                return new byte[0];


            try
            {
                file.Download(path);
            }
            catch (Exception)
            {
                return new byte[0];
            }


            byte[] buffer;
            using (FileStream fs = new FileStream(path, FileMode.Open))
            {
                buffer = new byte[fs.Length];
                fs.Read(buffer, 0, (int)fs.Length);     
            }

            return buffer;
        }


        public IEnumerable<User> GetUserByNameLike(string namepart)
        {
            return TransUtil.DoInTransaction(() => UserDao.FindByNameLike(namepart));
        }

        public IEnumerable<Music> GetPlaylistFull(string token)
        {
            IEnumerable<User> users = TransUtil.DoInTransaction(() => UserDao.FindAll());
            if (users == null || !users.Any())
                return new List<Music>();
            User u = GetUserForToken(token);
            IEnumerable<Music> playlist = TransUtil.DoInTransaction(() => MusicDao.FindAllForUser(u));
            return playlist;
        }
    }
}
